package net.eearley.redpoint.app;

import java.util.LinkedList;
import java.util.List;
import java.util.Stack;

import net.eearley.redpoint.app.exception.ATMException;
import net.eearley.redpoint.app.utils.SimpleLogger;

/**
 * The Class ATM.
 */
public class ATM {

	/**
	 * Instantiates a new aTM.
	 */
	public ATM() {

	}

	/**
	 * Payout.
	 * 
	 * @param inventory
	 *            the inventory
	 * @param payoutAmount
	 *            the payout amount
	 * 
	 * @return the integer
	 * 
	 * @throws ATMException
	 *             the ATM exception
	 */
	public Integer payout(Inventory inventory, Integer payoutAmount)
			throws ATMException {
		if (inventory.getTotalAmount() < payoutAmount)
			throw new ATMException("Insufficient Funds: " + payoutAmount);
		// force the order here to start withdrawl with big bills
		List<Denomination> ll = new LinkedList<Denomination>();
		ll.add(Denomination.HUNDRED);
		ll.add(Denomination.TWENTY);
		ll.add(Denomination.TEN);
		ll.add(Denomination.FIVE);
		ll.add(Denomination.SINGLE);
		SimpleLogger.logMessage("Dispensing:");
		//create a stack to grab the messages and pop em off to std.out
		Stack<String> stack = new Stack<String>();
		for (Denomination denomination : ll) {
			payoutAmount = pay(inventory, payoutAmount, denomination, stack);
		}
		while (!stack.empty()) { 
			SimpleLogger.logMessage(stack.pop());
		}
		return payoutAmount;

	}

	/**
	 * Pay.
	 * 
	 * @param inventory
	 *            the inventory
	 * @param payoutAmount
	 *            the payout amount
	 * @param denomination
	 *            the denomination
	 * 
	 * @return the int
	 */
	private int pay(Inventory inventory, Integer payoutAmount,
			Denomination denomination, Stack<String> stack) {
		int remainderToBePaid = payoutAmount.intValue() % denomination.getVal();
		int partialPayout = payoutAmount - remainderToBePaid;
		int billsPaid = partialPayout / denomination.getVal();
		int amountLeft = inventory.findCurrentValueByDenom(denomination)
				- partialPayout;
		int billsLeft = amountLeft / denomination.getVal();
		inventory.updateAmountOfBills(denomination, billsLeft);
		stack.push(denomination + ", " + billsPaid);
		return remainderToBePaid;

	}
}
